namespace GraphQL.Types;

/// <summary>
/// Provides basic capabilities for getting and setting arbitrary meta information.
/// This interface is implemented by numerous descendants like <see cref="GraphType"/>,
/// <see cref="FieldType"/>, <see cref="Schema"/> or others.
/// </summary>
public interface IProvideMetadata
{
    /// <summary>
    /// Provides all meta information as a key-value dictionary.
    /// </summary>
    Dictionary<string, object?> Metadata { get; }

    /// <summary>
    /// Gets a value by a given key. If there is no value for the given key, returns <paramref name="defaultValue"/>.
    /// </summary>
    /// <typeparam name="TType">Type of the value.</typeparam>
    /// <param name="key">String key.</param>
    /// <param name="defaultValue">It is used if there is no value for the given key.</param>
    /// <returns>Value of the specified type.</returns>
    TType GetMetadata<TType>(string key, TType defaultValue = default!);

    /// <summary>
    /// Gets a value by a given key. If there is no value for the given key, returns value obtained from <paramref name="defaultValueFactory"/>.
    /// </summary>
    /// <typeparam name="TType">Type of the value.</typeparam>
    /// <param name="key">String key.</param>
    /// <param name="defaultValueFactory">It is used if there is no value for the given key.</param>
    /// <returns>Value of the specified type.</returns>
    TType GetMetadata<TType>(string key, Func<TType> defaultValueFactory);

    /// <summary>
    /// Indicates whether there is meta information with the given key.
    /// </summary>
    /// <param name="key">String key.</param>
    /// <returns><see langword="true"/> if value for such key exists, otherwise <see langword="false"/>.</returns>
    bool HasMetadata(string key);
}
